home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-03-06 | 5.3 KB | 140 lines | [TEXT/GEOL] |
- Item forwarded by A33 to A34
-
- Item 0755410 7-Nov-89 15:03
-
- From: JOAQUIN1 Joaquin, James
-
- To: ATTACHMATE Attachmate, John Bartleson,PRT
-
- cc: BURBECK.S Burbeck, Steve
- MACAPP.TECH$ MacApp Technical
-
- Sub: More on USES (long)
-
- > If you have cycles, you have problems. Of course, this ruins one of the best
- > aspects (in my opinion) of OOL, namely systems are composed of interacting
- > objects which can be arranged arbitrarily. With Object Pascal, you must
- > impose some structure on these interactions.
-
- I agree. The development of modular, reusable code units is absolutely
- essential to successful large scale software development. Unfortunately, Object
- Pascal and its USES constraints present a major hurdle in implementing a
- modular design. The fact that fields of an object must be declared in the
- interface of a unit almost guarantees circular USES references when one tries
- to create objects that are composed of, or descendents of, objects in other
- units.
-
- The strategy that my group has adopted works as follows:
- Suppose you are creating a UNIT called MyView. This unit defines one object
- called TMyView and is comprised of two files, UMyView.p (interface) and
- UMyView.inc1.p (implementation).
-
- •The interface file (UMyView.p) would contain:
- TMyView = OBJECT(TView)
- fMyViewH: Handle;
- {-------------------field methods-------------------}
- PROCEDURE TMyView.SetIntField(theInt: Integer);
- FUNCTION TMyView.GetIntField : Integer;
- PROCEDURE TMyView.SetCustomButton(theCustomButton: TControl);
- FUNCTION TMyView.GetCustomButton : TControl;
- {----------------other methods here-----------------}
- PROCEDURE TMyView.Fields
- etc...
-
- •The implementation file (UMyView.inc1.p) would contain:
- MyViewInfoType = RECORD
- fIntField: INTEGER;
- fCustomButton: TControl;
- END; {MyViewInfoType}
- MyViewInfoPtr = ^MyViewInfoType;
- MyViewInfoH = ^MyViewInfoPtr;
-
- PROCEDURE TMyView.SetIntField(theInt: Integer);
- BEGIN
- MyViewInfoH(fMyViewH)^^.fIntField := theInt;
- END;
-
- FUNCTION TMyView.GetIntField : Integer;
- BEGIN
- GetIntField := MyViewInfoH(fMyViewH)^^.fIntField;
- END;
-
- PROCEDURE TMyView.SetCustomButton(theCustomButton: TControl);
- BEGIN
- {$IFC qDebug}
- IF NOT Member(theCustomButton, TCustomButton) THEN
- ProgramBreak('You must call SetCustomButton with a TCustomButton');
- {$ENDC}
- MyViewInfoH(fMyViewH)^^.fCustomButton := theCustomButton;
- END;
-
- FUNCTION TMyView.GetCustomButton : TControl;
- BEGIN
- GetCustomButton := MyViewInfoH(fMyViewH)^^.fCustomButton;
- END;
-
- PROCEDURE TMyView.Fields(PROCEDURE DoToField( fieldName: Str255;
- fieldAddr: Ptr; fieldType: INTEGER)); OVERRIDE;
- VAR
- temp: MyViewInfoType;
-
- BEGIN
- temp := MyViewInfoH(fMyViewH)^^;
- WITH temp DO
- BEGIN
- DoToField('fIntField', @fIntField, bInteger);
- DoToField('fCustomButton', @fCustomButton, bObject);
- END; {WITH}
- INHERITED Fields(DoToField);
- END;
-
- Notice here we get inspection of fields just as if they were defined publicly
- with the object. Also note that the fCustomButton is really an instance of
- TCustomButton (where TCustomButton is an object defined in UCustomButton which
- descends from TControl), even though our Get and Set methods use its nearest
- MacApp ancestor, TControl.
-
- The burden is on the programmer to CAST to and from TCustomButton when calling
- Get & Set, i.e.
- aCustomButton: TCustomButton;
- ...
- New(aCustomButton);
- SELF.SetCustomButton(TControl(aCustomButton);
- ---- OR --------
- aCustomButton := TCustomButton(SELF.GetCustomButton);
- ...
-
- I've found in many cases, especially when dealing with descendents of TView,
- one only needs to call methods of the MacApp ancestor class and can then call a
- Get method and assign it to a local var of type TView (or TControl, etc)
- without any casting. Method calls of the ancestor can then be made without the
- code ever explicitly referring to the descendent class.
-
- There are several PROS to this technique:
- 1) Since TMyView is composed of a TCustomButton it must include UCustomButton
- in its USES list, but NO OTHER UNIT using UMyView is required to use
- UCustomButton since it is explicitly referred to ONLY in the implementation.
- This has proved to be a HUGE gain when dealing with lots and lots of units and
- has allowed us to keep them small and modular.
- 2) Since the only field in TMyView is a handle to a private data structure,
- field assignment is bottlenecked through one SET method. If the behavior of
- SetIntField needed to be enhanced (to do some range checking, perhaps), new
- code would only need to be added to SetIntField and UMyView would be the only
- unit needing recompilation.
- 3) Having a predefined RECORD containing all the data that describes an object
- can be very useful when storing to a file and restoring from a file.
-
- Of course, there are also CONS:
- 1) Casting to and from the ancestor class adds work and potential confusion for
- the programmer.
- 2) There is obviously additional CPU overhead to call the Gets and Sets.
- 3) A fields record must be explicitly created for an object by the programmer,
- and must also be explicitly free'd by the programmer.
-
- The pros of this technique have definitely outweighed the cons for us!
-
- Hope this helps,
- James Joaquin
- Apple Computer
-
-